<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>虚拟DOM</title>
    <script src="script/react.development.js"></script>
    <script src="script/react-dom.development.js"></script>
    <script src="script/babel.min.js"></script>
</head>
<body>
<button id="btn">点我一下</button>
<hr>
<div id="root"></div>

<script type="text/babel">

    //创建一个数据
    const data = ['孙悟空', '猪八戒', '沙和尚'];

    // 创建列表
    const list = <ul>
        {/*data.map(item => <li key={item}>{item}</li>)*/}
        {data.map((item, index) => <li key={index}>{item}</li>)}
    </ul>;

    // 获取根元素
    const root = ReactDOM.createRoot(document.getElementById('root'));
    // 渲染元素
    root.render(list);

    /*
    *   在React我们操作的元素被称为React元素，并不是真正的原生DOM元素，
    *       React通过虚拟DOM 将React元素 和 原生DOM，进行映射，虽然操作的React元素，但是这些操作最终都会在真实DOM中体现出来
    *       虚拟DOM的好处：
    *           1.降低API复杂度
    *           2.解决兼容问题
    *           3.提升性能（减少DOM的不必要操作）
    *
    *   每当我们调用root.render()时，页面就会发生重新渲染
    *       React会通过diffing算法，将新的元素和旧的元素进行比较
    *       通过比较找到发生变化的元素，并且只对变化的元素进行修改，没有发生的变化不予处理
    * */
    document.getElementById('btn').onclick = function (){
        // 重新渲染页面
        //创建一个数据
        const data = ['唐僧', '孙悟空', '猪八戒', '沙和尚'];
        // 创建列表
        const list = <ul>
            {/*data.map(item => <li key={item}>{item}</li>)*/}
            {data.map((item, index) => <li key={index}>{item}</li>)}
        </ul>;
        // 渲染元素
        root.render(list);

        /*
        *   旧数据
        *       ul
        *           li>孙悟空
        *           li>猪八戒
        *           li>沙和尚
        *  新数据
        *       ul
        *           li>孙悟空
        *           li>猪八戒
        *           li>沙和尚
        *   比较两次数据时，React会先比较父元素，父元素如果不同，直接所有元素全部替换
        *       父元素一致，在去逐个比较子元素，直到找到所有发生变化的元素为止
        *   上例中，新旧两组数据完全一致，所以没有任何DOM对象被修改
        *
        *
        * 旧数据
        *       ul
        *           li>孙悟空
        *           li>猪八戒
        *           li>沙和尚
        *  新数据
        *       ul
        *           li>tom
        *           li>猪八戒
        *           li>沙和尚
        *
        *  上例中，只有第一个li发生变化，所以只有第一个li被修改，其他元素不变
        *
        *  当我们在JSX中显示数组中，数组中每一个元素都需要设置一个唯一key，否则控制台会显示红色警告
        *       重新渲染页面时，React会按照顺序依次比较对应的元素，当渲染一个列表时如果不指定key，同样也会按照顺序进行比较，
        *       如果列表的顺序永远不会发生变化，这么做当然没有问题，但是如果列表的顺序会发生变化，这可能会导致性能问题出现
        *
        *
        *   旧数据
        *       ul
        *           li>孙悟空
        *           li>猪八戒
        *           li>沙和尚
        *   新数据
        *       ul
        *           li>孙悟空
        *           li>猪八戒
        *           li>沙和尚
        *           li>唐僧
        *
        *   上例中，在列表的最后添加了一个新元素，并没有改变其他的元素的顺序，所以这种操作不会带来性能问题
        *
        *
        *
        *   旧数据
        *       ul
        *           li>孙悟空
        *           li>猪八戒
        *           li>沙和尚
        *   新数据
        *       ul
        *           li>唐僧
        *           li>孙悟空
        *           li>猪八戒
        *           li>沙和尚
        *
        *   上例中，在列表的最前边插入了一个新元素，其他元素内容并没有发生变化，
        *       但是由于新元素插入到了开始位置，其余元素的位置全都发生变化，而React默认是根据位置比较元素
        *       所以 此时，所有元素都会被修改
        *
        *   为了解决这个问题，React为列表设计了一个key属性，
        *       key的作用相当于ID，只是无法在页面中查看，当设置key以后，再比较元素时，
        *       就会比较相同key的元素，而不是按照顺序进行比较
        *   在渲染一个列表时，通常会给列表项设置一个唯一的key来避免上述问题
        *       （这个key在当前列表中唯一即可）
        *       注意：
        *           1.开发中一般会采用数据的id作为key
        *           2.尽量不要使用元素的index作为key
        *               索引会跟着元素顺序的改变而改变，所以使用索引做key跟没有key是一样的
        *                   唯一的不同就是，控制台的警告没了
        *               当元素的顺序不会发生变化时，用索引做key也没有什么问题
        *   旧数据
        *       ul
        *           li(key=孙悟空)>孙悟空
        *           li(key=猪八戒)>猪八戒
        *           li(key=沙和尚)>沙和尚
        *   新数据
        *       ul
        *           li(key=唐僧)>唐僧
        *           li(key=孙悟空)>孙悟空
        *           li(key=猪八戒)>猪八戒
        *           li(key=沙和尚)>沙和尚
        * */
    };



</script>
</body>
</html>
